package model;

import java.util.ArrayList;

/*
 * 
 * Classe qui organise le déroulement d'une partie
 * 
 * Attributs : elle a un nombre de tour, 2 joueurs et une liste d'observateur 
 * 
 * Fonctions : tourJoueur() : retourne le joueur du tour = tour paire => JoueurA / tour impaire => JoueurB
 *             partieTerminer() : retourne true si la partie est un des 2 joueurs n'a plus de point de vie
 *             vainqueur() : retourne le vainqueur du match
 *             piocher() : le joueur du tour pioche
 *             melanger() : le joueur du tour mélange
 *             upRessource() : met a jour les ressource du joueur du tour
 *             tourSuivant() : monte le tour de 1
 *             notifierObs() : actualise la vue du modèle 
 *             addObs()/removeObs() : ajoute/supprime un obeservateur
 *             afficherMain(Graphics g) : affiche toute les vatye de la main
 * 
 * 
 * /!\ Méthode obsolète /!\ : jouer()/jouerV2() : organise le déroulement du jeu
 *                            afficherTerrain() : affiche le terrain  
 * 
 */
/**
 *
 * @author Antoine Thorr, Joana Santos, Samy Rida, Vicky Ngo Pagbe
 */
public class Systeme {

  private int tour;
  private final Joueur j;
  private final IA ia;
  private final ArrayList<PartieCarteObservateur> listeObservateur;
  private boolean pioche;
  private final FileMessage fm;
  private boolean attaqueMode;
  private boolean finPartie;
  private CarteOffensive attaquant;

  /**
   *
   * @param j
   * @param ia
   */
  public Systeme(Joueur j, IA ia) {
    this.j = j;
    this.ia = ia;
    this.tour = 0;
    this.listeObservateur = new ArrayList<>();
    this.pioche = false;
    this.fm = new FileMessage();
    this.attaqueMode = false;

  }

  /**
   *
   * @return
   */
  public int getTour() {
    return this.tour;
  }

  /**
   *
   * @return
   */
  public Joueur getJoueur() {
    return this.j;
  }

  /**
   *
   * @return
   */
  public IA getIA() {
    return this.ia;
  }

  /**
   *
   * @return
   */
  public boolean aPioche() {
    return this.pioche;
  }

  /**
   *
   * @return
   */
  public Joueur tourJoueur() {
    if (this.tour % 2 == 0) {
      return this.j;
    } else {
      return this.ia;
    }
  }

  /**
   *
   * @return
   */
  public Joueur tourJoueurSuivant() {
    if (this.tourJoueur() instanceof IA) {
      return this.getJoueur();
    } else {
      return this.getIA();
    }
  }

  /**
   *
   * @return
   */
  public boolean partieTerminer() {
    return this.j.getVie() <= 0 || this.ia.getVie() <= 0;
  }

  /**
   *
   * @param joueur
   * @return
   */
  public boolean vainqueur(Joueur joueur) {
    return (joueur.getVie() <= 0);
  }

  /**
   *
   */
  public void piocher() {
    this.tourJoueur().piocher();
    this.pioche = true;
  }

  /**
   *
   */
  public void melanger() {
    this.tourJoueur().getDeck().melanger();
  }

  /**
   *
   */
  public void upRessource() {
    this.tourJoueur().upRessource();
    this.pioche = false;

  }

  /**
   *
   * @param m
   */
  public void addMessage(String m) {
    this.fm.addMessage(m);
    this.notifierObs();
  }

  /**
   *
   * @return
   */
  public FileMessage getFm() {
    return this.fm;
  }

  /**
   *
   */
  public void tourSuivant() {
    this.upRessource();
    this.tour++;
    if (this.tourJoueur() == this.j) {
      this.addMessage("TOUR DU JOUEUR");
      System.out.println("TOUR DU JOUEUR");
    } else {
      this.addMessage("TOUR DE L'IA");
      System.out.println("TOUR DE L'IA");
    }

    if (this.tourJoueur() instanceof IA) { //BEUG de sélection de carte à attaquer ?
      this.getIA().piocher();
      this.getIA().poseCarte();
      if (this.getIA().peutAttaquer(this.getJoueur())) { //l'IA attaque prioritairement les cartes que le joueur pose, et n'attaque qu'une fois (sinon remplacer if par while)
//        System.out.print("IA PEUT ATTAQUER");
//        this.attaqueMode = true; //facultatif ?
        this.attaquant = this.getIA().choixCarteAttaquante();
        this.getIA().selection(this.getIA().choixCarteAttaquable()); //on peut le mettre dans IA
//        System.out.println(", ATTAQUANT : " + this.attaquant);
        this.attaquerPhase2();
      } else if (this.getIA().peutAttaquerJoueur(this.getJoueur())) {
        this.attaquant = this.getIA().choixCarteAttaquante();
        this.attaquerPV();
      }
      this.tourSuivant();
    }
  }

  /**
   *
   * @param c
   */
  public void poserCarte(Carte c) {
    if (this.tourJoueur().carteSelectionne() != null) { //Si il y a une carte séléctionnée
      if (!this.tourJoueur().getPartieTerrain().isOnField(c)) { //Si elle n'est pas sur le terrain (donc est dans la main)
        if (this.aPioche()) { //Si le joueur a déjà pioché
          if (this.tourJoueur().getRessourceTemp() >= c.getCout()) { //Si le joueur a les ressources suffisantes pour la poser
            switch (c.getAttitude()) { //Selon son attitude
              case "offensive":
                //System.out.println("nbAttaque actuel : " + this.tourJoueur().getPartieTerrain().nbAttaque());
                if (this.tourJoueur().getPartieTerrain().nbAttaque() < 5) { //S'il reste une place pour une carte offensive
                  this.tourJoueur().poserCarteOffensive((CarteOffensive) c);
                  this.addMessage("Carte " + c.getNom() + " posée");
                } else {
                  this.addMessage("Vous ne pouvez plus poser de cartes d'attaque");
                }
                break;
              case "defensive":
                //System.out.println("nbDefense actuel : " + this.tourJoueur().getPartieTerrain().nbDefense());
                if (this.tourJoueur().getPartieTerrain().nbDefense() < 5) { //S'il reste une place pour une carte défensive
                  this.tourJoueur().poserCarteDefensive((CarteDefensive) c);
                  this.addMessage("Carte " + c.getNom() + " posée");
                } else {
                  this.addMessage("Vous ne pouvez plus poser de cartes de défense");
                }
                break;
            }
          } else {
            this.addMessage("Vous n'avez pas assez de ressources");
          }
        } else {
          this.addMessage("Vous devez piocher une carte avant");
        }
      } else {
        this.addMessage("Carte déjà sur le terrain");
      }
    } else {
      this.addMessage("Carte non séléctionnée ou à l'adversaire");
    }
//    this.notifierObs();
  }

  /**
   *
   * @return
   */
  public Carte isSelection() {
    return j.carteSelectionne();
  }

  /**
   *
   * @param c
   */
  public void selectionnerCarte(Carte c) {
    this.deselectionner();
    c.setSelection(true);
  }

  /**
   *
   */
  public void deselectionner() {
    this.j.getMain().deselectionner();
    this.ia.getMain().deselectionner();
    this.j.getPartieTerrain().deselectionner();
    this.ia.getPartieTerrain().deselectionner();
  }

  /**
   *
   */
  public void jouer() {
    this.j.getDeck().melanger();
    this.ia.getDeck().melanger();
    this.j.piocher(5);
    this.ia.piocher(5);
    this.addMessage("Bienvenue dans Hackunamadata");
    this.addMessage("Piochez une carte");
  }

  /**
   *
   */
  public void notifierObs() {
    for (PartieCarteObservateur pco : this.listeObservateur) {
//      System.out.println("ACTUALISATION");
      pco.actualiser();
    }
  }

  /**
   *
   * @param pco
   */
  public void addObs(PartieCarteObservateur pco) {
    this.listeObservateur.add(pco);
  }

  /**
   *
   * @param pco
   */
  public void removeObs(PartieCarteObservateur pco) {
    this.listeObservateur.remove(pco);
  }

  // /!\ METHODE DE DEBUG /!\

  /**
   *
   */
    public void afficherTerrain() {
    System.out.println("PdV = " + this.ia.getVie() + " cartes = " + this.ia.getMain() + " deck = " + this.ia.getDeck() + " cb = " + this.ia.getCorbeille());
    System.out.println(this.ia.getPartieTerrain());
    System.out.println("-----------------------------------------------------------");
    System.out.println(this.j.getPartieTerrain());
    System.out.println("PdV = " + this.j.getVie() + " cartes = " + this.j.getMain() + " deck = " + this.j.getDeck() + " cb = " + this.j.getCorbeille());
  }

  /**
   *
   */
  public void attaquerPhase1() { //Appui sur le bouton Attaquer
    if (this.j.carteSelectionne() != null) { // Je regarde si une carte est séléctionnée et si elle est bien à moi
      if (this.j.getPartieTerrain().isOnField(this.j.carteSelectionne())) { // Je regarde si la carte séléctionnée est sur le terrain
        if (this.j.carteSelectionne().getAttitude().equals("offensive")) { // Je regarde si c'est une carte offensive
          this.attaquant = (CarteOffensive) this.j.carteSelectionne();
          if (attaquant.getEtat() == Etat.enAttente) { // Je regarde son etat
            this.addMessage(attaquant.getNom() + " prêt à attaquer");
//            if (this.tourJoueurSuivant().getPartieTerrain().nbTotal() > 0) { //Si l'adversaire a des cartes sur le terrain
            this.addMessage("Sélectionnez une cible");
            this.attaqueMode = true;
//            } else { //S'il n'en a pas, attaque direct des PV
//              this.addMessage(this.j.carteSelectionne().getNom() + " attaque directement les PV de " + this.tourJoueurSuivant().getNomClasse());
            //this.tourJoueurSuivant().setVie(this.tourJoueurSuivant().getVie() - this.attaquant.getPointAttaque()); //Enlève PV selon carte
//            }
          } else {
            this.addMessage("La carte séléctionnée vient d'être posée ou a déjà attaqué");
          }
        } else {
          this.addMessage("La carte séléctionnée n'est pas une carte offensive");
        }
      } else {
        this.addMessage("La carte séléctionnée n'est pas sur le terrain");
      }
    } else {
      this.addMessage("Carte non séléctionnée ou à l'adversaire");
    }
  }

  /**
   *
   * @return
   */
  public boolean attaquerPhase2() { // Réalisation de l'attaque
    boolean succesAttaque = true;
    if (this.tourJoueurSuivant().carteSelectionne() != null) {
      switch (this.tourJoueurSuivant().carteSelectionne().getAttitude()) {
        case "offensive":
          CarteOffensive co = (CarteOffensive) this.tourJoueurSuivant().carteSelectionne();
          this.addMessage(attaquant.getNom() + " attaque " + co.getNom());
          co.setVie(co.getVie() - this.attaquant.getPointAttaque());
          this.attaquant.setEtat(Etat.aAttaque);
          if (co.getVie() <= 0) {
            this.tourJoueurSuivant().aLaCorbeille(co);
            this.addMessage(co.getNom() + " a été supprimé");
          }
          break;
        case "defensive":
          CarteDefensive cd = (CarteDefensive) this.tourJoueurSuivant().carteSelectionne();
          this.addMessage(attaquant.getNom() + " attaque " + cd.getNom());
          cd.setVie(cd.getVie() - this.attaquant.getPointAttaque());
          attaquant.setVie(this.attaquant.getVie() - cd.getPointContre());
          this.attaquant.setEtat(Etat.aAttaque);
          if (cd.getVie() <= 0) {
            this.tourJoueurSuivant().aLaCorbeille(cd);
            this.addMessage(cd.getNom() + " a été supprimé");
          }
          if (this.attaquant.getVie() <= 0) {
            this.tourJoueur().aLaCorbeille(this.attaquant);
            this.addMessage(this.attaquant.getNom() + " a été endommagé et supprimé");
          }
          break;
      }
    } else {
      this.addMessage("Attaque annulée");
      succesAttaque = false;
    }
    this.attaquant = null;
    this.attaqueMode = false;
//    this.notifierObs();
    return succesAttaque;
  }

  /**
   *
   * @return
   */
  public boolean isAttaqueMode() {
    return attaqueMode;
  }

  /**
   *
   */
  public void attaquerPV() {
    this.addMessage(attaquant.getNom() + " attaque directement " + this.tourJoueurSuivant().getNomClasse());
    this.tourJoueurSuivant().setVie(this.tourJoueurSuivant().getVie() - this.attaquant.getPointAttaque());
    this.attaquant.setEtat(Etat.aAttaque);
    if (this.vainqueur(this.tourJoueurSuivant())) {
      this.addMessage(this.tourJoueur().getNomClasse() + " A GAGNE LA PARTIE !");
    } else {
      this.attaquant = null;
      this.attaqueMode = false;
    }
  }
}
